home *** CD-ROM | disk | FTP | other *** search
- /* Top level of GNU C compiler
- Copyright (C) 1987, 1988, 1989 Free Software Foundation, Inc.
- Copyright (C) 1989, 1990 Apple Computer, Inc.
-
- This file is part of GNU CC.
-
- GNU CC is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-
- GNU CC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNU CC; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-
- /* This is the top level of cc1.
- It parses command args, opens files, invokes the various passes
- in the proper order, and counts the time used by each.
- Error messages and low-level interface to malloc also handled here. */
-
- #include "config.h"
- #include <stdio.h>
- #include <signal.h>
- #include <setjmp.h>
-
- #ifdef MPW
- /* MPW has its include files in slightly different places than Unix. */
- #include <types.h>
- #else
- #include <sys/types.h>
- #include <sys/stat.h>
- #endif /* MPW */
-
- #ifdef MPW
- #ifdef PERFORMANCE
- #include <Perf.h>
- #endif /* PERFORMANCE */
- #else /* not MPW */
- #ifdef USG
- #undef FLOAT
- #include <sys/param.h>
- /* This is for hpux. It is a real screw. They should change hpux. */
- #undef FLOAT
- #include <sys/times.h>
- #include <time.h> /* Correct for hpux at least. Is it good on other USG? */
- #undef FFS /* Some systems define this in param.h. */
- #else
- #ifndef VMS
- #include <sys/time.h>
- #include <sys/resource.h>
- #endif
- #endif
- #endif /* MPW */
-
- #include "input.h"
- #include "tree.h"
- #include "c-tree.h"
- #include "rtl.h"
- #include "flags.h"
-
- extern int yydebug;
-
- extern FILE *finput;
-
- extern int reload_completed;
- extern int rtx_equal_function_value_matters;
-
- extern void init_lex ();
- extern void init_decl_processing ();
- extern void init_tree ();
- extern void init_rtl ();
- extern void init_optabs ();
- extern void init_reg_sets ();
- extern void dump_flow_info ();
- extern void dump_local_alloc ();
-
- void rest_of_decl_compilation ();
- void error ();
- void error_with_file_and_line ();
- void fancy_abort ();
- void set_target_switch ();
- void print_target_switch_defaults ();
-
- /* Bit flags that specify the machine subtype we are compiling for.
- Bits are tested using macros TARGET_... defined in the tm-...h file
- and set by `-m...' switches. */
-
- int target_flags;
-
- /* Name of current original source file (what was input to cpp).
- This comes from each #-command in the actual input. */
-
- char *input_filename;
-
- /* Name of top-level original source file (what was input to cpp).
- This comes from the #-command at the beginning of the actual input.
- If there isn't any there, then this is the cc1 input file name. */
-
- char *main_input_filename;
-
- /* Current line number in real source file. */
-
- extern int lineno;
-
- /* Stack of currently pending input files. */
-
- struct file_stack *input_file_stack;
-
- /* Incremented on each change to input_file_stack. */
- int input_file_stack_tick;
-
- /* FUNCTION_DECL for function now being parsed or compiled. */
-
- extern tree current_function_decl;
-
- /* Name to use as base of names for dump output files. */
-
- char *dump_base_name;
-
- /* Flags saying which kinds of debugging dump have been requested. */
-
- int rtl_dump = 0;
- int rtl_dump_and_exit = 0;
- int jump_opt_dump = 0;
- int cse_dump = 0;
- int loop_dump = 0;
- int flow_dump = 0;
- int combine_dump = 0;
- int local_reg_dump = 0;
- int global_reg_dump = 0;
- int jump2_opt_dump = 0;
- int dbr_sched_dump = 0;
-
- /* 1 => write gdb debugging output (using symout.c). -g
- 2 => write dbx debugging output (using dbxout.c). -G
- 3 => write sdb debugging output (using sdbout.c). -g. */
-
- enum debugger write_symbols = NO_DEBUG;
-
- /* Nonzero means can use our own extensions to DBX format.
- Relevant only with write_symbols == DBX_DEBUG. */
-
- int use_gdb_dbx_extensions;
-
- /* Nonzero means do optimizations. -opt. */
-
- int optimize = 0;
-
- /* Nonzero means `char' should be signed. */
-
- int flag_signed_char;
-
- /* Nonzero means give an enum type only as many bytes as it needs. */
-
- int flag_short_enums;
-
- /* Nonzero for -fcaller-saves: allocate values in regs that need to
- be saved across function calls, if that produces overall better code.
- Optional now, so people can test it. */
-
- #ifdef DEFAULT_CALLER_SAVES
- int flag_caller_saves = 1;
- #else
- int flag_caller_saves = 0;
- #endif
-
- /* Nonzero for -fpcc-struct-return: return values the same way PCC does. */
-
- int flag_pcc_struct_return = 0;
-
- /* Nonzero for -fforce-mem: load memory value into a register
- before arithmetic on it. This makes better cse but slower compilation. */
-
- int flag_force_mem = 0;
-
- /* Nonzero for -fforce-addr: load memory address into a register before
- reference to memory. This makes better cse but slower compilation. */
-
- int flag_force_addr = 0;
-
- /* Nonzero for -fdefer-pop: don't pop args after each function call;
- instead save them up to pop many calls' args with one insns. */
-
- int flag_defer_pop = 1;
-
- /* Nonzero for -ffloat-store: don't allocate floats and doubles
- in extended-precision registers. */
-
- int flag_float_store = 0;
-
- /* Nonzero for -fcombine-regs:
- allow instruction combiner to combine an insn
- that just copies one reg to another. */
-
- int flag_combine_regs = 0;
-
- /* Nonzero enables strength-reduction in loop.c. */
-
- int flag_strength_reduce = 0;
-
- /* Nonzero for -fwritable-strings:
- store string constants in data segmentand don't uniquize them. */
-
- int flag_writable_strings = 0;
-
- /* Nonzero means don't put addresses of constant functions in registers.
- Used for compiling the Unix kernel, where strange substitutions are
- done on the assembly output. */
-
- int flag_no_function_cse = 0;
-
- /* Nonzero for -fomit-frame-pointer:
- don't make a frame pointer in simple functions that don't require one. */
-
- int flag_omit_frame_pointer = 0;
-
- /* Nonzero to inhibit use of define_optimization peephole opts. */
-
- int flag_no_peephole = 0;
-
- /* Nonzero means all references through pointers are volatile. */
-
- int flag_volatile;
-
- /* Nonzero means just do syntax checking; don't output anything. */
-
- int flag_syntax_only = 0;
-
- /* Nonzero means do stupid register allocation. -noreg.
- This and `optimize' are controlled by different switches in cc1,
- but normally cc controls them both with the -O switch. */
-
- int obey_regdecls = 0;
-
- /* Don't print functions as they are compiled and don't print
- times taken by the various passes. -quiet. */
-
- int quiet_flag = 0;
-
- /* Don't print warning messages. -w. */
-
- int inhibit_warnings = 0;
-
- /* Do print extra warnings (such as for uninitialized variables). -W. */
-
- int extra_warnings = 0;
-
- /* Nonzero to warn about unused local variables. */
-
- int warn_unused;
-
- /* Nonzero means warn about all declarations which shadow others. */
-
- int warn_shadow;
-
- /* Warn if a switch on an enum fails to have a case for every enum value. */
-
- int warn_switch;
-
- /* Nonzero means warn about any identifiers that match in the first N
- characters. The value N is in `id_clash_len'. */
-
- int warn_id_clash;
- int id_clash_len;
-
- /* Number of error messages and warning messages so far. */
-
- int errorcount = 0;
- int warningcount = 0;
- int sorrycount = 0;
-
- /* Name of program invoked, sans directories. */
-
- char *progname;
-
- /* Nonzero if generating code to do profiling. */
-
- int profile_flag = 0;
-
- /* Nonzero if generating code to do profiling on a line-by-line basis. */
-
- int profile_block_flag;
-
- /* Nonzero for -pedantic switch: warn about anything
- that standard spec forbids. */
-
- int pedantic = 0;
-
- /* Nonzero for -finline-functions: ok to inline functions that look like
- good inline candidates. */
-
- int flag_inline_functions;
-
- /* Nonzero for -fkeep-inline-functions: even if we make a function
- go inline everywhere, keep its defintion around for debugging
- purposes. */
-
- int flag_keep_inline_functions;
-
- /* Nonzero means make the text shared if supported. */
-
- int flag_shared_data;
-
- /* Nonzero means schedule into delayed branch slots if supported. */
-
- int flag_delayed_branch;
-
- /* Copy of arguments to main. */
- int save_argc;
- char **save_argv;
-
- /* Name for output file of assembly code, specified with -o. */
-
- char *asm_file_name;
-
- /* Name for output file of GDB symbol segment, specified with -symout. */
-
- char *sym_file_name;
-
- #ifdef APPLE_C
- /* Segment name for Macintosh. */
-
- char *segment_name = "Main";
-
- /* Flag indicating whether tracing is to happen. */
-
- int generate_trace_calls = 0;
-
- /* Flag indicating whether #pragma trace affects tracing. */
-
- int ignore_trace_pragmas = 0;
- #endif /* APPLE_C */
-
- #ifdef MPW
- #ifdef PERFORMANCE
- TP2PerfGlobals ThePGlobals;
- #endif /* PERFORMANCE */
- #endif /* MPW */
-
- /* Table of language-independent -f options.
- STRING is the option name. VARIABLE is the address of the variable.
- ON_VALUE is the value to store in VARIABLE
- if `-fSTRING' is seen as an option.
- (If `-fno-STRING' is seen as an option, the opposite value is stored.) */
-
- struct { char *string; int *variable; int on_value;} f_options[] =
- {
- {"float-store", &flag_float_store, 1},
- {"volatile", &flag_volatile, 1},
- {"defer-pop", &flag_defer_pop, 1},
- {"omit-frame-pointer", &flag_omit_frame_pointer, 1},
- {"strength-reduce", &flag_strength_reduce, 1},
- {"writable-strings", &flag_writable_strings, 1},
- {"peephole", &flag_no_peephole, 0},
- {"force-mem", &flag_force_mem, 1},
- {"force-addr", &flag_force_addr, 1},
- {"combine-regs", &flag_combine_regs, 1},
- {"function-cse", &flag_no_function_cse, 0},
- {"inline-functions", &flag_inline_functions, 1},
- {"keep-inline-functions", &flag_keep_inline_functions, 1},
- {"syntax-only", &flag_syntax_only, 1},
- {"shared-data", &flag_shared_data, 1},
- {"caller-saves", &flag_caller_saves, 1},
- {"pcc-struct-return", &flag_pcc_struct_return, 1},
- {"delayed-branch", &flag_delayed_branch, 1}
- };
-
- /* Output files for assembler code (real compiler output)
- and debugging dumps. */
-
- FILE *asm_out_file;
- FILE *rtl_dump_file;
- FILE *jump_opt_dump_file;
- FILE *cse_dump_file;
- FILE *loop_dump_file;
- FILE *flow_dump_file;
- FILE *combine_dump_file;
- FILE *local_reg_dump_file;
- FILE *global_reg_dump_file;
- FILE *jump2_opt_dump_file;
- FILE *dbr_sched_dump_file;
-
- /* Time accumulators, to count the total time spent in various passes. */
-
- int parse_time;
- int varconst_time;
- int integration_time;
- int jump_time;
- int cse_time;
- int loop_time;
- int flow_time;
- int combine_time;
- int local_alloc_time;
- int global_alloc_time;
- int dbr_sched_time;
- int final_time;
- int symout_time;
- int dump_time;
-
- /* Return time used so far, in microseconds. */
-
- int
- gettime ()
- {
- #ifdef MPW
- /* don't need a structure here */
-
- #else
- #ifdef USG
- struct tms tms;
- #else
- #ifndef VMS
- struct rusage rusage;
- #else /* VMS */
- struct
- {
- int proc_user_time;
- int proc_system_time;
- int child_user_time;
- int child_system_time;
- } vms_times;
- #endif
- #endif
- #endif /* MPW */
-
- if (quiet_flag)
- return 0;
-
- #ifdef MPW
- /* MPW's returns 1/60 sec ticks, so we do easy conversion to microseconds. */
- return (clock() * (1000000 / 60));
- #else
- #ifdef USG
- times (&tms);
- return (tms.tms_utime + tms.tms_stime) * (1000000 / HZ);
- #else
- #ifndef VMS
- getrusage (0, &rusage);
- return (rusage.ru_utime.tv_sec * 1000000 + rusage.ru_utime.tv_usec
- + rusage.ru_stime.tv_sec * 1000000 + rusage.ru_stime.tv_usec);
- #else /* VMS */
- times (&vms_times);
- return (vms_times.proc_user_time + vms_times.proc_system_time) * 10000;
- #endif
- #endif
- #endif /* MPW */
- }
-
- #define TIMEVAR(VAR, BODY) \
- do { int otime = gettime (); BODY; VAR += gettime () - otime; } while (0)
-
- void
- print_time (str, total)
- char *str;
- int total;
- {
- fprintf (stderr,
- "time in %s: %d.%06d\n",
- str, total / 1000000, total % 1000000);
- }
-
- /* Count an error or warning. Return 1 if the message should be printed. */
-
- int
- count_error (warningp)
- int warningp;
- {
- if (warningp && inhibit_warnings)
- return 0;
-
- if (warningp)
- warningcount++;
- else
- errorcount++;
-
- return 1;
- }
-
- /* Print a fatal error message. NAME is the text.
- Also include a system error message based on `errno'. */
-
- void
- pfatal_with_name (name)
- char *name;
- {
- fprintf (stderr, "%s: ", progname);
- perror (name);
- exit (35);
- }
-
- void
- fatal_io_error (name)
- char *name;
- {
- fprintf (stderr, "%s: %s: I/O error\n", progname, name);
- exit (35);
- }
-
- void
- fatal (s, v)
- char *s;
- int v;
- {
- error (s, v);
- exit (34);
- }
-
- /* Called from insn-extract to give a better error message when we
- don't have an insn to match what we are looking for, rather
- than just calling abort(). */
-
- void
- fatal_insn_not_found (insn)
- rtx insn;
- {
- error ("The following insn was not recognizable:", 0);
- debug_rtx (insn);
- abort ();
- }
-
- static int need_error_newline;
-
- /* Function of last error message;
- more generally, function such that if next error message is in it
- then we don't have to mention the function name. */
- static tree last_error_function = NULL;
-
- /* Used to detect when input_file_stack has changed since last described. */
- static int last_error_tick;
-
- /* Called when the start of a function definition is parsed,
- this function prints on stderr the name of the function. */
-
- void
- announce_function (decl)
- tree decl;
- {
- if (! quiet_flag)
- {
- fprintf (stderr, " %s", DECL_PRINT_NAME (decl));
- #ifdef MPW
- /* Newline after function name makes us look more like MPW C. */
- fprintf (stderr, "\n");
- #endif /* MPW */
- fflush (stderr);
- need_error_newline = 1;
- last_error_function = current_function_decl;
- }
- }
-
- /* Prints out, if necessary, the name of the current function
- which caused an error. Called from all error and warning functions. */
-
- void
- report_error_function (file)
- char *file;
- {
- struct file_stack *p;
-
- if (need_error_newline)
- {
- fprintf (stderr, "\n");
- need_error_newline = 0;
- }
-
- if (last_error_function != current_function_decl)
- {
- if (file)
- fprintf (stderr, "%s: ", file);
-
- if (current_function_decl == NULL)
- fprintf (stderr, "At top level:\n");
- else if (TREE_CODE (TREE_TYPE (current_function_decl)) == METHOD_TYPE)
- fprintf (stderr, "In method %s:\n",
- DECL_PRINT_NAME (current_function_decl));
- else
- fprintf (stderr, "In function %s:\n",
- DECL_PRINT_NAME (current_function_decl));
-
- last_error_function = current_function_decl;
- }
- if (input_file_stack && input_file_stack->next != 0
- && input_file_stack_tick != last_error_tick)
- {
- fprintf (stderr, "In file included");
- for (p = input_file_stack->next; p; p = p->next)
- {
- fprintf (stderr, " from %s:%d", p->name, p->line);
- if (p->next)
- fprintf (stderr, ",");
- }
- fprintf (stderr, ":\n");
- last_error_tick = input_file_stack_tick;
- }
- }
-
- /* Report an error at the current line number.
- S and V are a string and an arg for `printf'. */
-
- void
- error (s, v, v2)
- char *s;
- int v; /* @@also used as pointer */
- int v2; /* @@also used as pointer */
- {
- error_with_file_and_line (input_filename, lineno, s, v, v2);
- }
-
- /* Report an error at line LINE of file FILE.
- S and V are a string and an arg for `printf'. */
-
- void
- error_with_file_and_line (file, line, s, v, v2)
- char *file;
- int line;
- char *s;
- int v;
- int v2;
- {
- count_error (0);
-
- report_error_function (file);
-
- if (file)
- #ifdef MPW
- /* Print file and line so that they're valid MPW commands. */
- fprintf (stderr, "File \"%s\"; Line %d\t# ", file, line);
- #else
- fprintf (stderr, "%s:%d: ", file, line);
- #endif /* MPW */
- else
- fprintf (stderr, "%s: ", progname);
- fprintf (stderr, s, v, v2);
- fprintf (stderr, "\n");
- }
-
- /* Report an error at the declaration DECL.
- S and V are a string and an arg which uses %s to substitute the declaration name. */
-
- void
- error_with_decl (decl, s, v)
- tree decl;
- char *s;
- int v;
- {
- count_error (0);
-
- report_error_function (DECL_SOURCE_FILE (decl));
-
- #ifdef MPW
- /* Print file and line so that they're valid MPW commands. */
- fprintf (stderr, "File \"%s\"; Line %d\t# ",
- #else
- fprintf (stderr, "%s:%d: ",
- #endif /* MPW */
- DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl));
-
- if (DECL_PRINT_NAME (decl))
- fprintf (stderr, s, DECL_PRINT_NAME (decl), v);
- else if (DECL_NAME (decl))
- fprintf (stderr, s, IDENTIFIER_POINTER (DECL_NAME (decl)), v);
- else
- fprintf (stderr, s, "((anonymous))", v);
- fprintf (stderr, "\n");
- }
-
- /* Report an error at the line number of the insn INSN.
- S and V are a string and an arg for `printf'.
- This is used only when INSN is an `asm' with operands,
- and each ASM_OPERANDS records its own source file and line. */
-
- void
- error_for_asm (insn, s, v, v2)
- rtx insn;
- char *s;
- int v; /* @@also used as pointer */
- int v2; /* @@also used as pointer */
- {
- rtx temp;
- char *filename;
- int line;
- rtx body = PATTERN (insn);
- rtx asmop;
-
- /* Find the (or one of the) ASM_OPERANDS in the insn. */
- if (GET_CODE (body) == SET && GET_CODE (SET_SRC (body)) == ASM_OPERANDS)
- asmop = SET_SRC (body);
- else if (GET_CODE (body) == ASM_OPERANDS)
- asmop = body;
- else if (GET_CODE (body) == PARALLEL
- && GET_CODE (XVECEXP (body, 0, 0)) == SET)
- asmop = SET_SRC (XVECEXP (body, 0, 0));
- else if (GET_CODE (body) == PARALLEL
- && GET_CODE (XVECEXP (body, 0, 0)) == ASM_OPERANDS)
- asmop = XVECEXP (body, 0, 0);
-
- filename = ASM_OPERANDS_SOURCE_FILE (asmop);
- line = ASM_OPERANDS_SOURCE_LINE (asmop);
-
- error_with_file_and_line (filename, line, s, v, v2);
- }
-
- /* Report a warning at line LINE.
- S and V are a string and an arg for `printf'. */
-
- void
- warning_with_file_and_line (file, line, s, v, v2)
- char *file;
- int line;
- char *s;
- int v;
- int v2;
- {
- if (count_error (1) == 0)
- return;
-
- report_error_function (file);
-
- if (file)
- #ifdef MPW
- /* Print file and line so that they're valid MPW commands. */
- fprintf (stderr, "File \"%s\"; Line %d\t# ", file, line);
- #else
- fprintf (stderr, "%s:%d: ", file, line);
- #endif /* MPW */
- else
- fprintf (stderr, "%s: ", progname);
-
- fprintf (stderr, "warning: ");
- fprintf (stderr, s, v, v2);
- fprintf (stderr, "\n");
- }
-
- /* Report a warning at the current line number.
- S and V are a string and an arg for `printf'. */
-
- void
- warning (s, v, v2)
- char *s;
- int v; /* @@also used as pointer */
- int v2;
- {
- warning_with_file_and_line (input_filename, lineno, s, v, v2);
- }
-
- /* Report a warning at the declaration DECL.
- S is string which uses %s to substitute the declaration name.
- V is a second parameter that S can refer to. */
-
- void
- warning_with_decl (decl, s, v)
- tree decl;
- char *s;
- int v;
- {
- if (count_error (1) == 0)
- return;
-
- report_error_function (DECL_SOURCE_FILE (decl));
-
- #ifdef MPW
- /* Print file and line so that they're valid MPW commands. */
- fprintf (stderr, "File \"%s\"; Line %d\t# ",
- #else
- fprintf (stderr, "%s:%d: ",
- #endif /* MPW */
- DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl));
-
- fprintf (stderr, "warning: ");
- if (DECL_PRINT_NAME (decl))
- fprintf (stderr, s, DECL_PRINT_NAME (decl), v);
- else if (DECL_NAME (decl))
- fprintf (stderr, s, IDENTIFIER_POINTER (DECL_NAME (decl)), v);
- else
- fprintf (stderr, s, "((anonymous))", v);
- fprintf (stderr, "\n");
- }
-
- /* Apologize for not implementing some feature.
- S, V, and V2 are a string and args for `printf'. */
-
- void
- sorry (s, v, v2)
- char *s;
- int v, v2;
- {
- sorrycount++;
- if (input_filename)
- #ifdef MPW
- /* Print file and line so that they're valid MPW commands. */
- fprintf (stderr, "File \"%s\"; Line %d\t# ", input_filename, lineno);
- #else
- fprintf (stderr, "%s:%d: ", input_filename, lineno);
- #endif /* MPW */
- else
- fprintf (stderr, "%s: ", progname);
-
- fprintf (stderr, "sorry, not implemented: ");
- fprintf (stderr, s, v, v2);
- fprintf (stderr, "\n");
- }
-
- /* Apologize for not implementing some feature, then quit.
- S, V, and V2 are a string and args for `printf'. */
-
- void
- really_sorry (s, v, v2)
- char *s;
- int v, v2;
- {
- if (input_filename)
- #ifdef MPW
- /* Print file and line so that they're valid MPW commands. */
- fprintf (stderr, "File \"%s\"; Line %d\t# ", input_filename, lineno);
- #else
- fprintf (stderr, "%s:%d: ", input_filename, lineno);
- #endif /* MPW */
- else
- fprintf (stderr, "c++: ");
-
- fprintf (stderr, "sorry, not implemented: ");
- fprintf (stderr, s, v, v2);
- fatal (" (fatal)\n");
- }
-
- /* More 'friendly' abort that prints the line and file.
- config.h can #define abort fancy_abort if you like that sort of thing. */
-
- void
- fancy_abort ()
- {
- #ifdef MPW
- /* Make sure no output still buffered up, then zap into Macsbug. */
- printf("Ack!\n");
-